﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
using System.Collections.Generic;

namespace Jzy.Workflow.Code
{
    public class FlowLine
    {
        private FlowNode _fromNode;
        private FlowNode _toNode;

        private Path _line;
        private LineType _lineType;

        public LineType LineType
        {
            get { return _lineType; }
            set { _lineType = value; }
        }

        /// <summary>
        /// 数据库主键
        /// </summary>
        public int PKID
        {
            get;
            set;
        }

        public FlowNode FromNode
        {
            get
            {
                return _fromNode;
            }
            set
            {
                _fromNode = value;
                _fromNode.Lines.Add(this);
            }
        }

        public FlowNode ToNode
        {
            get
            {
                return _toNode;
            }
            set
            {
                _toNode = value;
                _toNode.Lines.Add(this);
            }
        }

        public Path Line
        {
            get
            {
                return _line;
            }
        }

        public FlowLine()
        {
            _line = new Path();
            _line.Stroke = new SolidColorBrush(FlowColors.Green);
            _line.StrokeThickness = 1.5;
            _line.MouseEnter += new MouseEventHandler(_line_MouseEnter);
            _line.MouseLeave += new MouseEventHandler(_line_MouseLeave);
        }
        public FlowLine(FlowNode start, FlowNode end, LineType lineType)
            : this()
        {
            FromNode = start;
            ToNode = end;
            LineType = lineType;
        }

        void _line_MouseLeave(object sender, MouseEventArgs e)
        {
            GlobalVar.ActiveElement = null;
            _line.Stroke = new SolidColorBrush(FlowColors.Green);
        }

        void _line_MouseEnter(object sender, MouseEventArgs e)
        {
            GlobalVar.ActiveElement = this;
            _line.Stroke = new SolidColorBrush(FlowColors.Yellow);
            Canvas.SetZIndex(_line, GlobalVar.ZIndex);
        }

        public static FlowLine Parse(string xml,List<FlowNode> nodes)
        {
            return Parse(XElement.Parse(xml), nodes);
        }

        public static FlowLine Parse(XElement xml, List<FlowNode> nodes)
        {
            FlowLine line = new FlowLine();
            line.PKID = int.Parse(xml.Element("ID").Value);
            line.LineType = (LineType)int.Parse(xml.Element("TypeID").Value);
            for (int i = 0; i < nodes.Count; i++)
            {
                if (nodes[i].PKID == int.Parse(xml.Element("FromNodeID").Value))
                {
                    line.FromNode = nodes[i];
                }
                else if(nodes[i].PKID == int.Parse(xml.Element("ToNodeID").Value))
                {
                    line.ToNode = nodes[i];
                }
            }
            return line;
        }

        public void Draw()
        {
            if (_lineType == LineType.折线)
            {
                DrawPolyline();
            }
            else
            {
                DrawStraightline();
            }
        }

        /// <summary>
        /// 画直线
        /// </summary>
        private void DrawStraightline()
        {
            _line.Visibility = Visibility.Visible;

            Point start = new Point();
            Point end = new Point();

            PathGeometry geometry = new PathGeometry();
            PathFigure line = new PathFigure();
            line.StartPoint = start;
            PathFigure arrow = new PathFigure();

            if (Math.Abs(_fromNode.CenterPosition.X - _toNode.CenterPosition.X) > (_fromNode.Width / 2 + _toNode.Width / 2))
            {
                int flag = (_fromNode.CenterPosition.X > _toNode.CenterPosition.X) ? -1 : 1;
                start.X = _fromNode.CenterPosition.X + _fromNode.Width / 2 * flag;
                start.Y = _fromNode.CenterPosition.Y;

                end.X = _toNode.CenterPosition.X + _toNode.Width / 2 * (-flag);
                end.Y = _toNode.CenterPosition.Y;

                line.StartPoint = start;
                line.Segments.Add(new LineSegment() { Point = end });

                double radian = Math.Atan((end.Y - start.Y) / (end.X - start.X)) - Math.Atan(0.5);
                double x = end.X + 6.7 * Math.Cos(radian) * (-flag);
                double y = end.Y + 6.7 * Math.Sin(radian) * (-flag);

                arrow.StartPoint = new Point(x, y);
                arrow.Segments.Add(new LineSegment() { Point = end });

                radian = Math.Atan((end.Y - start.Y) / (end.X - start.X)) + Math.Atan(0.5);
                x = end.X + 6.7 * Math.Cos(radian) * (-flag);
                y = end.Y + 6.7 * Math.Sin(radian) * (-flag);
                arrow.Segments.Add(new LineSegment() { Point = new Point(x, y) });

            }
            else
            {
                if (Math.Abs(_fromNode.CenterPosition.Y - _toNode.CenterPosition.Y) > (_fromNode.Height / 2 + _toNode.Height / 2))
                {
                    int flag = (_fromNode.CenterPosition.Y > _toNode.CenterPosition.Y) ? -1 : 1;
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y + _fromNode.Height / 2 * flag;

                    end.X = _toNode.CenterPosition.X;
                    end.Y = _toNode.CenterPosition.Y + _toNode.Height / 2 * (-flag);

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = end });

                    flag = (_fromNode.CenterPosition.X > _toNode.CenterPosition.X) ? -1 : 1;
                    double radian = Math.Atan((end.Y - start.Y) / (end.X - start.X)) - Math.Atan(0.5);
                    double x = end.X + 6.7 * Math.Cos(radian) * (-flag);
                    double y = end.Y + 6.7 * Math.Sin(radian) * (-flag);

                    arrow.StartPoint = new Point(x, y);
                    arrow.Segments.Add(new LineSegment() { Point = end });

                    radian = Math.Atan((end.Y - start.Y) / (end.X - start.X)) + Math.Atan(0.5);
                    x = end.X + 6.7 * Math.Cos(radian) * (-flag);
                    y = end.Y + 6.7 * Math.Sin(radian) * (-flag);
                    arrow.Segments.Add(new LineSegment() { Point = new Point(x, y) });
                }
                else
                {
                    _line.Visibility = Visibility.Collapsed;
                }
            }

            geometry.Figures.Add(line);
            geometry.Figures.Add(arrow);
            _line.Data = geometry;


            //        //画箭头线了
            //        PathGeometry geometry = new PathGeometry();
            //        PathFigure figure = new PathFigure();
            //        figure.StartPoint = pathBeginPoint;
            //        figure.Segments.Add(new LineSegment() { Point = pathEndPoint });

            //        geometry.Figures.Add(figure);



            //        figure = new PathFigure();

            //        double radian = Math.Atan((pathEndPoint.Y - pathBeginPoint.Y) / (pathEndPoint.X - pathBeginPoint.X)) - Math.Atan(0.5);
            //        double x = pathEndPoint.X + 6.7 * Math.Cos(radian) * ((beginCenter.X > endCenter.X) ? 1 : -1);
            //        double y = pathEndPoint.Y + 6.7 * Math.Sin(radian) * ((beginCenter.X > endCenter.X) ? 1 : -1);
            //        figure.StartPoint = new Point(x, y);

            //        figure.Segments.Add(new LineSegment() { Point = pathEndPoint });

            //        radian = Math.Atan((pathEndPoint.Y - pathBeginPoint.Y) / (pathEndPoint.X - pathBeginPoint.X)) + Math.Atan(0.5);
            //        x = pathEndPoint.X + 6.7 * Math.Cos(radian) * ((beginCenter.X > endCenter.X) ? 1 : -1);
            //        y = pathEndPoint.Y + 6.7 * Math.Sin(radian) * ((beginCenter.X > endCenter.X) ? 1 : -1);

            //        figure.Segments.Add(new LineSegment() { Point = new Point(x, y) });

            //        geometry.Figures.Add(figure);

            //        flowPath.Data = geometry;

            //    }
            //    else
            //    {
            //        flowPath.Visibility = Visibility.Collapsed;
            //    }
            //}

        }

        private void DrawPolyline()
        {
            _line.Visibility = Visibility.Visible;

            LineDirection direct = LineDirection.Up;
            if (Math.Abs(_fromNode.CenterPosition.X - _toNode.CenterPosition.X) < _toNode.Width / 2)
            {
                if (Math.Abs(_fromNode.CenterPosition.Y - _toNode.CenterPosition.Y) < (_toNode.Height + _fromNode.Height) / 2)
                {
                    _line.Visibility = Visibility.Collapsed;
                    return;
                }

                if (_fromNode.CenterPosition.Y > _toNode.CenterPosition.Y)//从上面出去
                {
                    direct = LineDirection.Up;
                }
                else
                {
                    direct = LineDirection.Down;
                }

            }
            else if (Math.Abs(_fromNode.CenterPosition.Y - _toNode.CenterPosition.Y) < _fromNode.Height / 2)//垂直方向上有重叠
            {
                if (Math.Abs(_fromNode.CenterPosition.X - _toNode.CenterPosition.X) < (_fromNode.Width + _toNode.Width) / 2)
                {
                    _line.Visibility = Visibility.Collapsed;
                    return;
                }

                if (_fromNode.CenterPosition.X > _toNode.CenterPosition.X)//从左面出去
                {
                    direct = LineDirection.Left;
                }
                else
                {
                    direct = LineDirection.Right;
                }
            }
            else
            {
                if (_fromNode.CenterPosition.X > _toNode.CenterPosition.X && _fromNode.CenterPosition.Y > _toNode.CenterPosition.Y)
                {
                    direct = LineDirection.LeftUp;
                }
                else if (_fromNode.CenterPosition.X < _toNode.CenterPosition.X && _fromNode.CenterPosition.Y > _toNode.CenterPosition.Y)//右上方
                {
                    direct = LineDirection.RightUp;
                }
                else if (_fromNode.CenterPosition.X > _toNode.CenterPosition.X && _fromNode.CenterPosition.Y < _toNode.CenterPosition.Y)//左下方
                {
                    direct = LineDirection.LeftDown;
                }
                else
                {
                    direct = LineDirection.RightDown;
                }
            }

            Point start = new Point();
            Point end = new Point();
            Point middle = new Point();

            PathGeometry geometry = new PathGeometry();
            PathFigure line = new PathFigure();
            line.StartPoint = start;
            PathFigure arrow = new PathFigure();

            switch (direct)
            {
                case LineDirection.Up:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y - _fromNode.Height / 2;

                    end.X = start.X;
                    if (_toNode.Type == NodeType.结束)
                    {
                        double tmp = Math.Sqrt((1d - Math.Pow(end.X - _toNode.CenterPosition.X, 2) / Math.Pow(FlowNode.NODE_WIDTH / 2, 2)) * Math.Pow(FlowNode.NODE_HEIGHT / 2, 2));
                        end.Y = _toNode.CenterPosition.Y + tmp;
                    }
                    else
                    {
                        end.Y = _toNode.CenterPosition.Y + _toNode.Height / 2;
                    }

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X - 3, end.Y + 6);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X + 3, end.Y + 6) });
                    break;
                case LineDirection.Down:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y + _fromNode.Height / 2;

                    end.X = start.X;
                    if (_toNode.Type == NodeType.结束)
                    {
                        double tmp = Math.Sqrt((1d - Math.Pow(end.X - _toNode.CenterPosition.X, 2) / Math.Pow(FlowNode.NODE_WIDTH / 2, 2)) * Math.Pow(FlowNode.NODE_HEIGHT / 2, 2));
                        end.Y = _toNode.CenterPosition.Y - tmp;
                    }
                    else
                    {
                        end.Y = _toNode.CenterPosition.Y - _toNode.Height / 2;
                    }

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X - 3, end.Y - 6);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X + 3, end.Y - 6) });
                    break;
                case LineDirection.Left:
                    start.Y = _toNode.CenterPosition.Y;
                    if (_fromNode.Type == NodeType.拟稿)
                    {
                        double tmp = Math.Sqrt((1d - Math.Pow(start.Y - _fromNode.CenterPosition.Y, 2) / Math.Pow(FlowNode.NODE_HEIGHT / 2, 2)) * Math.Pow(FlowNode.NODE_WIDTH / 2, 2));
                        start.X = _fromNode.CenterPosition.X - tmp;
                    }
                    else
                    {
                        start.X = _fromNode.CenterPosition.X - _fromNode.Width / 2;
                    }

                    end.X = _toNode.CenterPosition.X + _toNode.Width / 2;
                    end.Y = start.Y;

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X + 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X + 6, end.Y + 3) });
                    break;
                case LineDirection.Right:
                    start.Y = _toNode.CenterPosition.Y;
                    if (_fromNode.Type == NodeType.拟稿)
                    {
                        double tmp = Math.Sqrt((1d - Math.Pow(start.Y - _fromNode.CenterPosition.Y, 2) / Math.Pow(FlowNode.NODE_HEIGHT / 2, 2)) * Math.Pow(FlowNode.NODE_WIDTH / 2, 2));
                        start.X = _fromNode.CenterPosition.X + tmp;
                    }
                    else
                    {
                        start.X = _fromNode.CenterPosition.X + _fromNode.Width / 2;
                    }

                    line.StartPoint = start;
                    end.X = _toNode.CenterPosition.X - _toNode.Width / 2;
                    end.Y = start.Y;

                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X - 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X - 6, end.Y + 3) });
                    break;
                case LineDirection.LeftUp:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y - _fromNode.Height / 2;

                    line.StartPoint = start;
                    middle.X = _fromNode.CenterPosition.X;
                    middle.Y = _toNode.CenterPosition.Y;

                    end.X = _toNode.CenterPosition.X + _toNode.Width / 2;
                    end.Y = _toNode.CenterPosition.Y;

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = middle });
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X + 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X + 6, end.Y + 3) });
                    break;
                case LineDirection.RightUp:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y - _fromNode.Height / 2;

                    middle.X = _fromNode.CenterPosition.X;
                    middle.Y = _toNode.CenterPosition.Y;

                    end.X = _toNode.CenterPosition.X - _toNode.Width / 2;
                    end.Y = middle.Y;

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = middle });
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X - 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X - 6, end.Y + 3) });
                    break;
                case LineDirection.LeftDown:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y + _fromNode.Height / 2;

                    middle.X = _fromNode.CenterPosition.X;
                    middle.Y = _toNode.CenterPosition.Y;

                    end.X = _toNode.CenterPosition.X + _toNode.Width / 2;
                    end.Y = _toNode.CenterPosition.Y;

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = middle });
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X + 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X + 6, end.Y + 3) });
                    break;
                case LineDirection.RightDown:
                    start.X = _fromNode.CenterPosition.X;
                    start.Y = _fromNode.CenterPosition.Y + _fromNode.Height / 2;

                    middle.X = _fromNode.CenterPosition.X;
                    middle.Y = _toNode.CenterPosition.Y;

                    end.X = _toNode.CenterPosition.X - _toNode.Width / 2;
                    end.Y = _toNode.CenterPosition.Y;

                    line.StartPoint = start;
                    line.Segments.Add(new LineSegment() { Point = middle });
                    line.Segments.Add(new LineSegment() { Point = end });

                    arrow.StartPoint = new Point(end.X - 6, end.Y - 3);
                    arrow.Segments.Add(new LineSegment() { Point = end });
                    arrow.Segments.Add(new LineSegment() { Point = new Point(end.X - 6, end.Y + 3) });
                    break;


            }

            geometry.Figures.Add(line);
            geometry.Figures.Add(arrow);
            _line.Data = geometry;

        }


        public override bool Equals(object obj)
        {
            if (((FlowLine)obj).PKID == this.PKID)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool operator ==(FlowLine a, FlowLine b)
        {
            return a.PKID == b.PKID;
        }

        public static bool operator !=(FlowLine a, FlowLine b)
        {
            return a.PKID != b.PKID;
        }

        public override int GetHashCode()
        {
            return this.PKID;
        }
    }
}
